package com.ymatou.iapi.settlement.testcase;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.ymatou.iapi.optrade.parameter.enums.LogisticsTypeEnum;
import com.ymatou.iapi.optrade.parameter.req.AgreeRefundReq;
import com.ymatou.iapi.optrade.parameter.req.ApplyRefundReq;
import com.ymatou.iapi.optrade.parameter.vo.SalesRefundInfoVo;
import com.ymatou.iapi.optrade.resp.TradingServiceResp;
import com.ymatou.iapi.optrade.service.AgreeRefundCall;
import com.ymatou.iapi.optrade.service.RefundService;
import com.ymatou.iapi.settlement.parameter.SettleRefundCommissionBean;
import com.ymatou.iapi.settlement.parameter.SettleSellerIncomeAndChargeCommissionBean;
import com.ymatou.iapi.settlement.service.SettleRefundCommissionCall;
import com.ymatou.iapi.settlement.service.SettleSellerIncomeAndChargeCommissionCall;
import com.ymatou.iapi.synctrade.service.TradingSyncService;
import com.ymt.core.tool.Logger;
import com.ymt.utils.annotation.TestCase;
import com.ymt.utils.annotation.TestSuite;
import com.ymt.utils.tag.P1;
import com.ymttest.business.service.PayGateWayCallService;
import com.ymttest.business.service.YMTTrading.TradingCallService;
import com.ymttest.business.service.YMTTrading.TradingPlaceOrderCallService;
import com.ymttest.database.model.Account;
import com.ymttest.database.model.AccountEntry;
import com.ymttest.database.model.YmtCommissionDetail;
import com.ymttest.database.sharding.db.sharding.model.RefundBillPo;
import com.ymttest.database.sharding.db.sqlwapper.OrderShardingWapper;
import com.ymttest.database.sqlwapper.AccountWapper;
import com.ymttest.database.sqlwapper.YmtCommissionDetailWapper;

/**
 * 结算退佣接口 FreeMaker Template自动生成代码
 */
@TestSuite
public class Ts_SettleRefundCommission {

	private static SettleRefundCommissionBean settlerefundcommissionBean;
	private static SettleRefundCommissionCall settlerefundcommissionCall;

	private static SettleSellerIncomeAndChargeCommissionBean settlesellerincomeandchargecommissionBean;
	private static SettleSellerIncomeAndChargeCommissionCall settlesellerincomeandchargecommissionCall;
	
	private static AgreeRefundReq salesrefundsuccessReq = new AgreeRefundReq();
	private static AgreeRefundCall salesrefundsuccessCall = new AgreeRefundCall();
	
	private static OrderShardingWapper orderShardingWapper = new OrderShardingWapper();

	@BeforeClass
	public static void setUp() {
		Logger.createResultFile("结算退佣接口");
	}

	@Before
	public void caseUp() {
		settlerefundcommissionBean = new SettleRefundCommissionBean();
		settlerefundcommissionCall = new SettleRefundCommissionCall();

		settlesellerincomeandchargecommissionBean = new SettleSellerIncomeAndChargeCommissionBean();
		settlesellerincomeandchargecommissionCall = new SettleSellerIncomeAndChargeCommissionCall();
	}

	@AfterClass
	public static void tearDown() {
		Logger.generateResult(settlerefundcommissionCall.getOpurl());
		orderShardingWapper.activeDeadCommunicationsLink(orderShardingWapper);
	}

	@After
	public void caseDown() {
		Logger.end();
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Test
	@Category({P1.class})
	@TestCase
	public void Tc_SettleRefundCommission_001() {
		Logger.start(true, "结算退佣成功, 单个商品全额退款");
		try {
			// 创建一个拼邮的订单
			TradingServiceResp placeOrderResp = TradingPlaceOrderCallService
					.placeOrderWithLogisticsType(LogisticsTypeEnum.OVERSEAS_DELIVERY);

			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			long sellerId = placeOrderResp.getOrderList().get(0).getSellerId();
			long userId = placeOrderResp.getUserId();
			long tradingId = placeOrderResp.getTradingId();

			//支付
			Long thirdTradingId = TradingCallService.payOrder(userId,
					BigDecimal.ZERO, tradingId, "13");
			
			PayGateWayCallService.notifyCall("13",
					thirdTradingId.toString(),
					placeOrderResp.getPayableAmount().subtract(BigDecimal.ZERO).toString(),
					(int) userId);
			TradingSyncService.getSyncResult(orderId);
			
			Thread.sleep(5000);
			
			// 接单
			TradingCallService.sellerAcceptOrder(sellerId, orderId);
			TradingSyncService.getSyncResult(orderId);
			
			// 拼邮国际段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 1);
			TradingSyncService.getSyncResult(orderId);
			
			// 拼邮国内段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 3);
			
			TradingCallService.confirmReceive(userId, orderId);
			
			Thread.sleep(5000);
			
			// 结算收入和扣佣
			settlesellerincomeandchargecommissionBean.setOrderId(orderId);
			settlesellerincomeandchargecommissionCall
					.setData(settlesellerincomeandchargecommissionBean);
			settlesellerincomeandchargecommissionCall.callService();

			Thread.sleep(10000);

			// 第一个商品全款退款
			ApplyRefundReq applyRefundReq = RefundService.applyRefund(placeOrderResp.getOrderList().get(0), 0);

			salesrefundsuccessReq.setOrderId(orderId);

			int i = 0;

			for (SalesRefundInfoVo salesRefundInfoVo : applyRefundReq
					.getSalesRefundInfoList()) {

				salesrefundsuccessReq.setRefundBillNo(salesRefundInfoVo
						.getRefundBillNo());
				salesrefundsuccessCall.setData(salesrefundsuccessReq);

				Logger.comment(String.format("orderid: %s 第 %s 个商品 退款执行",
						orderId, i + 1));

				salesrefundsuccessCall.callService();

				Logger.verifyEquals("true",
						salesrefundsuccessCall.getString("success"),
						"验证退货退款成功返回");
				i++;
			}

			Thread.sleep(4000);
			
			PayGateWayCallService.refundNotifyCall("13",
					thirdTradingId.toString(), (int) userId);

			// 退款成功消息是异步操作，所以需要等待一段时间
			Thread.sleep(2500l);
			String refundBillNo = applyRefundReq
					.getSalesRefundInfoList().get(0).getRefundBillNo();
			
			RefundBillPo actualRefundBillPo = orderShardingWapper
					.selectRefundBillByBillNo(refundBillNo);

			//String OrderInfoId = (String) refunds.get(0).get("OrderInfoId");
			BigDecimal RefundedAmountOfCash = actualRefundBillPo.getTotalAmount(); // 退货退款单退回金额
			int RefundProductNum = actualRefundBillPo.getProductCount(); // 可退佣金商品数量

			List<YmtCommissionDetail> details = new YmtCommissionDetailWapper()
					.selectByOrderId(orderId);
			List<YmtCommissionDetail> x = details.stream()
					.filter(a -> a.getOrderInfoId().equals(orderId + "000"))
					.collect(Collectors.toList());
			YmtCommissionDetail refundCommition = x.stream()
					.filter(a -> a.getInvoiceType() == 5)
					.collect(Collectors.toList()).get(0);
			YmtCommissionDetail billConmtion = x.stream()
					.filter(a -> a.getInvoiceType() == 4)
					.collect(Collectors.toList()).get(0);

			BigDecimal RealPayAmountPerProd = refundCommition
					.getRealPayAmountPerProd(); // 单件商品实际支付金额
			BigDecimal CommissionPerProd = refundCommition
					.getCommissionPerProd(); // 单件商品实际收佣金额
			BigDecimal SingleCommissionRate = refundCommition
					.getSingleCommissionRate(); // 退佣比例

			Logger.verifyEquals(billConmtion.getCommissionPerProd(),
					refundCommition.getCommissionPerProd(),
					"验证退佣的单个商品佣金CommissionPerProd");
			// 可退佣金商品数量=min[int（退货退款单退回金额/单件商品实际支付金额），退回数量]
			int expProdNumOfCommission = Integer.min(RefundedAmountOfCash
					.divide(RealPayAmountPerProd, BigDecimal.ROUND_DOWN)
					.intValue(), RefundProductNum);
			Logger.verifyEquals(expProdNumOfCommission,
					refundCommition.getProdNumOfCommission(),
					"验证Ymt_CommissionDetail表可退佣金商品数量");
			// 退回商品佣金= [单件商品实际收佣金额－单件商品已返佣金]×可退佣金商品数量×退佣比例
			BigDecimal expCommissionAmount = CommissionPerProd
					.multiply(new BigDecimal(expProdNumOfCommission))
					.multiply(SingleCommissionRate)
					.divide(new BigDecimal(1), 2, BigDecimal.ROUND_HALF_UP);
			Logger.verifyEquals(expCommissionAmount,
					refundCommition.getCommissionAmount(),
					"验证Ymt_CommissionDetail表的退佣金额");
			// 结算退佣前取用户账户表的余额
			Account accountInfoBeforeRefundCommition = new AccountWapper()
					.selectAccountInfoByUserId((int)sellerId, 1).get(0);
			BigDecimal fAvailAmountBeforeRefundCommition = accountInfoBeforeRefundCommition
					.getAvailAmount();
			Logger.comment("前置数据准备结束");
			
			settlerefundcommissionBean.setOrderId(orderId);
			settlerefundcommissionBean.setRefundBillNo(refundBillNo);
			settlerefundcommissionCall.setData(settlerefundcommissionBean);
			// 结算退佣
			settlerefundcommissionCall.callService();
			Logger.verifyEquals("ok",
					settlerefundcommissionCall.getReturnData(),
					"验证SettlerefundcommissionCall返回结果");

			Map m1 = new HashMap();
			m1.put("bizno", refundBillNo);

			com.ymttest.database.model.AccountEntry entry = new AccountWapper()
					.selectAccountEntryByBizNo(m1).get(0);

			Logger.verifyEquals(expCommissionAmount, entry.getAmount(),
					"验证支付流水表退佣金额");
			BigDecimal expAvailAmount = fAvailAmountBeforeRefundCommition
					.add(expCommissionAmount);
			// 结算退佣后取用户账户表的余额
			Account accountInfoAfterRefundCommition = new AccountWapper()
					.selectAccountInfoByUserId((int)sellerId, 1).get(0);
			BigDecimal fAvailAmountAfterRefundCommition = accountInfoAfterRefundCommition
					.getAvailAmount();

			Logger.verifyEquals(expAvailAmount,
					fAvailAmountAfterRefundCommition,
					"检查退佣结算成功后ymt_AccountInfo的用户余额");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Test
	@Category({P1.class})
	@TestCase
	public void Tc_SettleRefundCommission_002() {
		Logger.start(true, "结算退佣成功, 单个商品部分退款");
		try {
			// 创建一个拼邮的订单
			TradingServiceResp placeOrderResp = TradingPlaceOrderCallService
					.placeOrderWithLogisticsType(LogisticsTypeEnum.OVERSEAS_DELIVERY);

			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			long sellerId = placeOrderResp.getOrderList().get(0).getSellerId();
			long userId = placeOrderResp.getUserId();
			long tradingId = placeOrderResp.getTradingId();
			
			//支付
			Long thirdTradingId = TradingCallService.payOrder(userId,
					BigDecimal.ZERO, tradingId, "13");
			
			PayGateWayCallService.notifyCall("13",
					thirdTradingId.toString(),
					placeOrderResp.getPayableAmount().subtract(BigDecimal.ZERO).toString(),
					(int) userId);
			TradingSyncService.getSyncResult(orderId);
			
			Thread.sleep(5000);
			
			// 接单
			TradingCallService.sellerAcceptOrder(sellerId, orderId);
			TradingSyncService.getSyncResult(orderId);
			
			// 拼邮国际段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 1);
			TradingSyncService.getSyncResult(orderId);
			
			// 拼邮国内段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 3);
			
			TradingCallService.confirmReceive(userId, orderId);
			
			Thread.sleep(5000);
			
			// 结算收入和扣佣
			settlesellerincomeandchargecommissionBean.setOrderId(orderId);
			settlesellerincomeandchargecommissionCall
					.setData(settlesellerincomeandchargecommissionBean);
			settlesellerincomeandchargecommissionCall.callService();

			Thread.sleep(25000);

			// 第一个商品部分退款
			ApplyRefundReq applyRefundReq = RefundService
					.applyRefund(placeOrderResp.getOrderList().get(0), 1);
			salesrefundsuccessReq.setOrderId(orderId);
			int i = 0;

			for (SalesRefundInfoVo salesRefundInfoVo : applyRefundReq
					.getSalesRefundInfoList()) {

				salesrefundsuccessReq.setRefundBillNo(salesRefundInfoVo
						.getRefundBillNo());
				salesrefundsuccessCall.setData(salesrefundsuccessReq);

				Logger.comment(String.format("orderid: %s 第 %s 个商品 退款执行",
						orderId, i + 1));

				salesrefundsuccessCall.callService();

				Logger.verifyEquals("true",
						salesrefundsuccessCall.getString("success"),
						"验证退货退款成功返回");
				i++;
			}

			Thread.sleep(4000);
			
			PayGateWayCallService.refundNotifyCall("13",
					thirdTradingId.toString(), (int) userId);
			
			String refundBillNo = applyRefundReq.getSalesRefundInfoList().get(0).getRefundBillNo();
			
			// 生成确认收货后的退货退款所引起的退佣结算单前记录账户余额
			Account accountInfoBeforeRefundCommition = new AccountWapper()
					.selectAccountInfoByUserId((int)sellerId, 1).get(0);

			BigDecimal fAvailAmountBeforeRefundCommition = accountInfoBeforeRefundCommition
					.getAvailAmount();

			Account accountInfoAfterRefundCommition = new AccountWapper()
					.selectAccountInfoByUserId((int)sellerId, 1).get(0);

			BigDecimal fAvailAmountAfterRefundCommition = accountInfoAfterRefundCommition
					.getAvailAmount();

			Logger.verifyEquals(fAvailAmountBeforeRefundCommition,
					fAvailAmountAfterRefundCommition, "验证未发生退佣结算前，余额不变");

			String OrderInfoId = orderId + "000";

			List<YmtCommissionDetail> details = new YmtCommissionDetailWapper()
					.selectByOrderId(orderId);
			List<YmtCommissionDetail> x = details.stream()
					.filter(a -> a.getOrderInfoId().equals(OrderInfoId))
					.collect(Collectors.toList());
			YmtCommissionDetail refundCommition = x.stream()
					.filter(a -> a.getInvoiceType() == 5)
					.collect(Collectors.toList()).get(0);
			YmtCommissionDetail billConmtion = x.stream()
					.filter(a -> a.getInvoiceType() == 4)
					.collect(Collectors.toList()).get(0);

			Logger.verifyEquals(billConmtion.getCommissionPerProd(),
					refundCommition.getCommissionPerProd(),
					"验证退佣的单个商品佣金CommissionPerProd");
			// 部分退款，可退商品数量设置为0
			Logger.verifyEquals(1, refundCommition.getProdNumOfCommission(),
					"验证Ymt_CommissionDetail表可退佣金商品数量");
			// 部分退款，可退佣金金额为0.00
			Logger.verifyEquals(new BigDecimal("10.00"), refundCommition
					.getCommissionAmount(), "验证Ymt_CommissionDetail表的退佣金额");
			Logger.comment("前置数据准备结束");

			settlerefundcommissionBean.setOrderId(orderId);
			settlerefundcommissionBean.setRefundBillNo(refundBillNo);
			settlerefundcommissionCall.setData(settlerefundcommissionBean);
			
			// 结算退佣
			settlerefundcommissionCall.callService();
			
			Logger.verifyEquals("ok",
					settlerefundcommissionCall.getReturnData(),
					"验证SettlerefundcommissionCall返回结果");
			
			Map m1 = new HashMap();
			m1.put("bizno", refundBillNo);
			
			List<AccountEntry> entrys = new AccountWapper()
					.selectAccountEntryByBizNo(m1);

			Logger.verifyEquals(1, entrys.size(), "验证资金流水表中退佣的记录");

		} catch (Exception e) {
			Logger.fail(e);
		}
	}
}
